#include "nuklear.h"
#include "nuklear_internal.h"

/* ==============================================================
 *
 *                          COLOR
 *
 * ===============================================================*/
NK_INTERN int
nk_parse_hex(const char* p, int length) {
  int i = 0;
  int len = 0;
  while (len < length) {
    i <<= 4;
    if (p[len] >= 'a' && p[len] <= 'f')
      i += ((p[len] - 'a') + 10);
    else if (p[len] >= 'A' && p[len] <= 'F')
      i += ((p[len] - 'A') + 10);
    else
      i += (p[len] - '0');
    len++;
  }
  return i;
}
NK_API nk_color
nk_rgba(int r, int g, int b, int a) {
  nk_color ret;
  ret.r = (nk_byte)NK_CLAMP(0, r, 255);
  ret.g = (nk_byte)NK_CLAMP(0, g, 255);
  ret.b = (nk_byte)NK_CLAMP(0, b, 255);
  ret.a = (nk_byte)NK_CLAMP(0, a, 255);
  return ret;
}
NK_API nk_color
nk_rgb_hex(const char* rgb) {
  nk_color col;
  const char* c = rgb;
  if (*c == '#')
    c++;
  col.r = (nk_byte)nk_parse_hex(c, 2);
  col.g = (nk_byte)nk_parse_hex(c + 2, 2);
  col.b = (nk_byte)nk_parse_hex(c + 4, 2);
  col.a = 255;
  return col;
}
NK_API nk_color
nk_rgba_hex(const char* rgb) {
  nk_color col;
  const char* c = rgb;
  if (*c == '#')
    c++;
  col.r = (nk_byte)nk_parse_hex(c, 2);
  col.g = (nk_byte)nk_parse_hex(c + 2, 2);
  col.b = (nk_byte)nk_parse_hex(c + 4, 2);
  col.a = (nk_byte)nk_parse_hex(c + 6, 2);
  return col;
}
NK_API void nk_color_hex_rgba(char* output, nk_color col) {
#define NK_TO_HEX(i) ((i) <= 9 ? '0' + (i) : 'A' - 10 + (i))
  output[0] = (char)NK_TO_HEX((col.r & 0xF0) >> 4);
  output[1] = (char)NK_TO_HEX((col.r & 0x0F));
  output[2] = (char)NK_TO_HEX((col.g & 0xF0) >> 4);
  output[3] = (char)NK_TO_HEX((col.g & 0x0F));
  output[4] = (char)NK_TO_HEX((col.b & 0xF0) >> 4);
  output[5] = (char)NK_TO_HEX((col.b & 0x0F));
  output[6] = (char)NK_TO_HEX((col.a & 0xF0) >> 4);
  output[7] = (char)NK_TO_HEX((col.a & 0x0F));
  output[8] = '\0';
#undef NK_TO_HEX
}
NK_API void nk_color_hex_rgb(char* output, nk_color col) {
#define NK_TO_HEX(i) ((i) <= 9 ? '0' + (i) : 'A' - 10 + (i))
  output[0] = (char)NK_TO_HEX((col.r & 0xF0) >> 4);
  output[1] = (char)NK_TO_HEX((col.r & 0x0F));
  output[2] = (char)NK_TO_HEX((col.g & 0xF0) >> 4);
  output[3] = (char)NK_TO_HEX((col.g & 0x0F));
  output[4] = (char)NK_TO_HEX((col.b & 0xF0) >> 4);
  output[5] = (char)NK_TO_HEX((col.b & 0x0F));
  output[6] = '\0';
#undef NK_TO_HEX
}
NK_API nk_color
nk_rgba_iv(const int* c) {
  return nk_rgba(c[0], c[1], c[2], c[3]);
}
NK_API nk_color
nk_rgba_bv(const nk_byte* c) {
  return nk_rgba(c[0], c[1], c[2], c[3]);
}
NK_API nk_color
nk_rgb(int r, int g, int b) {
  nk_color ret;
  ret.r = (nk_byte)NK_CLAMP(0, r, 255);
  ret.g = (nk_byte)NK_CLAMP(0, g, 255);
  ret.b = (nk_byte)NK_CLAMP(0, b, 255);
  ret.a = (nk_byte)255;
  return ret;
}
NK_API nk_color
nk_rgb_iv(const int* c) {
  return nk_rgb(c[0], c[1], c[2]);
}
NK_API nk_color
nk_rgb_bv(const nk_byte* c) {
  return nk_rgb(c[0], c[1], c[2]);
}
NK_API nk_color
nk_rgba_u32(nk_uint in) {
  nk_color ret;
  ret.r = (in & 0xFF);
  ret.g = ((in >> 8) & 0xFF);
  ret.b = ((in >> 16) & 0xFF);
  ret.a = (nk_byte)((in >> 24) & 0xFF);
  return ret;
}
NK_API nk_color
nk_rgba_f(float r, float g, float b, float a) {
  nk_color ret;
  ret.r = (nk_byte)(NK_SATURATE(r) * 255.0f);
  ret.g = (nk_byte)(NK_SATURATE(g) * 255.0f);
  ret.b = (nk_byte)(NK_SATURATE(b) * 255.0f);
  ret.a = (nk_byte)(NK_SATURATE(a) * 255.0f);
  return ret;
}
NK_API nk_color
nk_rgba_fv(const float* c) {
  return nk_rgba_f(c[0], c[1], c[2], c[3]);
}
NK_API nk_color
nk_rgba_cf(nk_colorf c) {
  return nk_rgba_f(c.r, c.g, c.b, c.a);
}
NK_API nk_color
nk_rgb_f(float r, float g, float b) {
  nk_color ret;
  ret.r = (nk_byte)(NK_SATURATE(r) * 255.0f);
  ret.g = (nk_byte)(NK_SATURATE(g) * 255.0f);
  ret.b = (nk_byte)(NK_SATURATE(b) * 255.0f);
  ret.a = 255;
  return ret;
}
NK_API nk_color
nk_rgb_fv(const float* c) {
  return nk_rgb_f(c[0], c[1], c[2]);
}
NK_API nk_color
nk_rgb_cf(nk_colorf c) {
  return nk_rgb_f(c.r, c.g, c.b);
}
NK_API nk_color
nk_hsv(int h, int s, int v) {
  return nk_hsva(h, s, v, 255);
}
NK_API nk_color
nk_hsv_iv(const int* c) {
  return nk_hsv(c[0], c[1], c[2]);
}
NK_API nk_color
nk_hsv_bv(const nk_byte* c) {
  return nk_hsv(c[0], c[1], c[2]);
}
NK_API nk_color
nk_hsv_f(float h, float s, float v) {
  return nk_hsva_f(h, s, v, 1.0f);
}
NK_API nk_color
nk_hsv_fv(const float* c) {
  return nk_hsv_f(c[0], c[1], c[2]);
}
NK_API nk_color
nk_hsva(int h, int s, int v, int a) {
  float hf = ((float)NK_CLAMP(0, h, 255)) / 255.0f;
  float sf = ((float)NK_CLAMP(0, s, 255)) / 255.0f;
  float vf = ((float)NK_CLAMP(0, v, 255)) / 255.0f;
  float af = ((float)NK_CLAMP(0, a, 255)) / 255.0f;
  return nk_hsva_f(hf, sf, vf, af);
}
NK_API nk_color
nk_hsva_iv(const int* c) {
  return nk_hsva(c[0], c[1], c[2], c[3]);
}
NK_API nk_color
nk_hsva_bv(const nk_byte* c) {
  return nk_hsva(c[0], c[1], c[2], c[3]);
}
NK_API nk_colorf
nk_hsva_colorf(float h, float s, float v, float a) {
  int i;
  float p, q, t, f;
  nk_colorf out = {0, 0, 0, 0};
  if (s <= 0.0f) {
    out.r = v;
    out.g = v;
    out.b = v;
    out.a = a;
    return out;
  }
  h = h / (60.0f / 360.0f);
  i = (int)h;
  f = h - (float)i;
  p = v * (1.0f - s);
  q = v * (1.0f - (s * f));
  t = v * (1.0f - s * (1.0f - f));

  switch (i) {
    case 0:
    default:
      out.r = v;
      out.g = t;
      out.b = p;
      break;
    case 1:
      out.r = q;
      out.g = v;
      out.b = p;
      break;
    case 2:
      out.r = p;
      out.g = v;
      out.b = t;
      break;
    case 3:
      out.r = p;
      out.g = q;
      out.b = v;
      break;
    case 4:
      out.r = t;
      out.g = p;
      out.b = v;
      break;
    case 5:
      out.r = v;
      out.g = p;
      out.b = q;
      break;
  }
  out.a = a;
  return out;
}
NK_API nk_colorf
nk_hsva_colorfv(float* c) {
  return nk_hsva_colorf(c[0], c[1], c[2], c[3]);
}
NK_API nk_color
nk_hsva_f(float h, float s, float v, float a) {
  nk_colorf c = nk_hsva_colorf(h, s, v, a);
  return nk_rgba_f(c.r, c.g, c.b, c.a);
}
NK_API nk_color
nk_hsva_fv(const float* c) {
  return nk_hsva_f(c[0], c[1], c[2], c[3]);
}
NK_API nk_uint
nk_color_u32(nk_color in) {
  nk_uint out = (nk_uint)in.r;
  out |= ((nk_uint)in.g << 8);
  out |= ((nk_uint)in.b << 16);
  out |= ((nk_uint)in.a << 24);
  return out;
}
NK_API void nk_color_f(float* r, float* g, float* b, float* a, nk_color in) {
  NK_STORAGE const float s = 1.0f / 255.0f;
  *r = (float)in.r * s;
  *g = (float)in.g * s;
  *b = (float)in.b * s;
  *a = (float)in.a * s;
}
NK_API void nk_color_fv(float* c, nk_color in) {
  nk_color_f(&c[0], &c[1], &c[2], &c[3], in);
}
NK_API nk_colorf
nk_color_cf(nk_color in) {
  nk_colorf o;
  nk_color_f(&o.r, &o.g, &o.b, &o.a, in);
  return o;
}
NK_API void nk_color_d(double* r, double* g, double* b, double* a, nk_color in) {
  NK_STORAGE const double s = 1.0 / 255.0;
  *r = (double)in.r * s;
  *g = (double)in.g * s;
  *b = (double)in.b * s;
  *a = (double)in.a * s;
}
NK_API void nk_color_dv(double* c, nk_color in) {
  nk_color_d(&c[0], &c[1], &c[2], &c[3], in);
}
NK_API void nk_color_hsv_f(float* out_h, float* out_s, float* out_v, nk_color in) {
  float a;
  nk_color_hsva_f(out_h, out_s, out_v, &a, in);
}
NK_API void nk_color_hsv_fv(float* out, nk_color in) {
  float a;
  nk_color_hsva_f(&out[0], &out[1], &out[2], &a, in);
}
NK_API void nk_colorf_hsva_f(float* out_h, float* out_s,
                             float* out_v, float* out_a, nk_colorf in) {
  float chroma;
  float K = 0.0f;
  if (in.g < in.b) {
    const float t = in.g;
    in.g = in.b;
    in.b = t;
    K = -1.f;
  }
  if (in.r < in.g) {
    const float t = in.r;
    in.r = in.g;
    in.g = t;
    K = -2.f / 6.0f - K;
  }
  chroma = in.r - ((in.g < in.b) ? in.g : in.b);
  *out_h = NK_ABS(K + (in.g - in.b) / (6.0f * chroma + 1e-20f));
  *out_s = chroma / (in.r + 1e-20f);
  *out_v = in.r;
  *out_a = in.a;
}
NK_API void nk_colorf_hsva_fv(float* hsva, nk_colorf in) {
  nk_colorf_hsva_f(&hsva[0], &hsva[1], &hsva[2], &hsva[3], in);
}
NK_API void nk_color_hsva_f(float* out_h, float* out_s,
                            float* out_v, float* out_a, nk_color in) {
  nk_colorf col;
  nk_color_f(&col.r, &col.g, &col.b, &col.a, in);
  nk_colorf_hsva_f(out_h, out_s, out_v, out_a, col);
}
NK_API void nk_color_hsva_fv(float* out, nk_color in) {
  nk_color_hsva_f(&out[0], &out[1], &out[2], &out[3], in);
}
NK_API void nk_color_hsva_i(int* out_h, int* out_s, int* out_v,
                            int* out_a, nk_color in) {
  float h, s, v, a;
  nk_color_hsva_f(&h, &s, &v, &a, in);
  *out_h = (nk_byte)(h * 255.0f);
  *out_s = (nk_byte)(s * 255.0f);
  *out_v = (nk_byte)(v * 255.0f);
  *out_a = (nk_byte)(a * 255.0f);
}
NK_API void nk_color_hsva_iv(int* out, nk_color in) {
  nk_color_hsva_i(&out[0], &out[1], &out[2], &out[3], in);
}
NK_API void nk_color_hsva_bv(nk_byte* out, nk_color in) {
  int tmp[4];
  nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in);
  out[0] = (nk_byte)tmp[0];
  out[1] = (nk_byte)tmp[1];
  out[2] = (nk_byte)tmp[2];
  out[3] = (nk_byte)tmp[3];
}
NK_API void nk_color_hsva_b(nk_byte* h, nk_byte* s, nk_byte* v, nk_byte* a, nk_color in) {
  int tmp[4];
  nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in);
  *h = (nk_byte)tmp[0];
  *s = (nk_byte)tmp[1];
  *v = (nk_byte)tmp[2];
  *a = (nk_byte)tmp[3];
}
NK_API void nk_color_hsv_i(int* out_h, int* out_s, int* out_v, nk_color in) {
  int a;
  nk_color_hsva_i(out_h, out_s, out_v, &a, in);
}
NK_API void nk_color_hsv_b(nk_byte* out_h, nk_byte* out_s, nk_byte* out_v, nk_color in) {
  int tmp[4];
  nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in);
  *out_h = (nk_byte)tmp[0];
  *out_s = (nk_byte)tmp[1];
  *out_v = (nk_byte)tmp[2];
}
NK_API void nk_color_hsv_iv(int* out, nk_color in) {
  nk_color_hsv_i(&out[0], &out[1], &out[2], in);
}
NK_API void nk_color_hsv_bv(nk_byte* out, nk_color in) {
  int tmp[4];
  nk_color_hsv_i(&tmp[0], &tmp[1], &tmp[2], in);
  out[0] = (nk_byte)tmp[0];
  out[1] = (nk_byte)tmp[1];
  out[2] = (nk_byte)tmp[2];
}
